#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include "main.h"
#include "usr_cfg.h"
#include "zlog.h"
#include "lm75a_thread.h"


#define PLATFORM_GPIO_UIO_DEV 				"/dev/uio1"
#define PLATFORM_GPIO_UIO_ADDR     	 		"/sys/class/uio/uio1/maps/map0/addr"
#define PLATFORM_GPIO_UIO_SIZE      		"/sys/class/uio/uio1/maps/map0/size"

platform_gpio_handle			gpio_dev;
extern sys_runtime				sys_rt;	

#define LM75A_TEMP_PATH 	"/sys/bus/i2c/devices/0-0048/hwmon/hwmon0/temp1_input"
#define PS_TEMP_PATH 		"/sys/bus/iio/devices/iio:device0/in_temp0_ps_temp_raw"
#define PL_TEMP_PATH 		"/sys/bus/iio/devices/iio:device0/in_temp2_pl_temp_raw"
// ((float)ps_temp)*509.3140064/65536.0-280.2308787);

void platform_gpio_axi_init(sys_cfg_info *sys, platform_gpio_handle *platform_gpio)
{
	char wind_uio_addr_buf[18], wind_uio_size_buf[18];
	int wind_uio_fd, wind_addr_fd, wind_size_fd;
	
	wind_uio_fd  = open(PLATFORM_GPIO_UIO_DEV, O_RDWR);
    wind_addr_fd = open(PLATFORM_GPIO_UIO_ADDR, O_RDONLY);
    wind_size_fd = open(PLATFORM_GPIO_UIO_SIZE, O_RDONLY);
	if (wind_addr_fd < 0 || wind_size_fd < 0 || wind_uio_fd < 0) {
		dzlog_error("zynq platform gpio uio device file open error!");
		perror("zynq platform gpio uio device file open error!\n");
        exit(EXIT_FAILURE);
    }

	read(wind_addr_fd, wind_uio_addr_buf, sizeof(wind_uio_addr_buf));
    read(wind_size_fd, wind_uio_size_buf, sizeof(wind_uio_size_buf));

	platform_gpio->platform_axi_uio_fd = wind_uio_fd;
	platform_gpio->platform_axi_base_addr = strtoul(wind_uio_addr_buf, NULL, 16);		//16代表16进制读取
    // platform_gpio->platform_axi_addr_size = strtoul(wind_uio_size_buf, NULL, 16);	//16代表16进制读取
    platform_gpio->platform_axi_addr_size = 0x10000;									//固定64KB空间

	printf("platform_gpio->platform_axi_uio_fd is %d\n", platform_gpio->platform_axi_uio_fd);
	printf("platform_gpio->platform_axi_base_addr is %#x\n", platform_gpio->platform_axi_base_addr);
	printf("platform_gpio->platform_axi_addr_size is %#x\n",  platform_gpio->platform_axi_addr_size);

	platform_gpio->platform_axi_virt_addr =  mmap(NULL, platform_gpio->platform_axi_addr_size, PROT_READ | PROT_WRITE,
								MAP_SHARED, platform_gpio->platform_axi_uio_fd, 0);
	
    if (platform_gpio->platform_axi_virt_addr == MAP_FAILED) {
        fprintf(stderr, "platform_gpio->platform_axi_virt_addr mmap: %s\n", strerror(errno));
		dzlog_error("platform_gpio->platform_axi_virt_addr mmap failed!");
        exit(FAILURE);
    }

	printf("platform_axi_virt_addr is %p\n", platform_gpio->platform_axi_virt_addr);
	printf("############################################################\n");
}


inline __attribute__((always_inline)) void gpio_axi_reg_set(platform_gpio_handle *pwind, uint32_t offset, uint32_t val) 
{
    *(pwind->platform_axi_virt_addr + offset) = val;
}



//lm75a环境温度采集线程
void *lm75a_temp_thread(void *arc)
{
	thread_status *s = NULL;
	int ps_temp, pl_temp, lm75a_temp;
	FILE *fp1, *fp2, *fp3;

	printf("lm75a ambient temperature measure thread is starting!\n");
	
	if (arc == NULL)
		return NULL;

	s = (thread_status*)arc;
	s->status = TS_ALIVE;

	platform_gpio_axi_init(&sys_cfg, &gpio_dev);
	gpio_axi_reg_set(&gpio_dev, 0x04, 0x00000000);		// GPIO1全部配置为输出
	gpio_axi_reg_set(&gpio_dev, 0x00, 0x00000002);		// 风扇1停止
	gpio_axi_reg_set(&gpio_dev, 0x0C, 0x00000000);		// GPIO2全部配置为输出
	gpio_axi_reg_set(&gpio_dev, 0x08, 0x00000002);		// 风扇2停止

	if (sys_cfg.debug == ON) {
		printf("lm75a and zynqmp ps pl ambient temperature measure thread init done\n");
	}

 	
	while (s->status) {
		fp1 = fopen(PS_TEMP_PATH, "r");
	 	if (fp1 == NULL) {
	 		printf("zynqmp ps temperature fp1 open %s failed!\n", PS_TEMP_PATH);
	 	}
		fscanf(fp1, "%d", &ps_temp);

		fp2 = fopen(PL_TEMP_PATH, "r");
	 	if (fp2 == NULL) {
	 		printf("zynqmp pl temperature fp2 open %s failed!\n", PL_TEMP_PATH);
	 	}
		fscanf(fp2, "%d", &pl_temp);

		fp3 = fopen(LM75A_TEMP_PATH, "r");
	 	if (fp3 == NULL) {
	 		printf("lm75a ambient temperature fp3 open %s failed!\n", LM75A_TEMP_PATH);
	 	}
		fscanf(fp3, "%d", &lm75a_temp);

		sys_rt.sys_ps_temp = ((float)ps_temp) * 509.314f / 65536.0f - 280.2309;
		sys_rt.sys_pl_temp = ((float)pl_temp) * 509.314f / 65536.0f - 280.2309;
		sys_rt.sys_amb_temp = ((float)lm75a_temp) / 1000.0f; 		// translate into real temperature

		if (sys_cfg.debug == ON)
		{
	        printf("current zynqmp ps temperature is: %f\n", sys_rt.sys_ps_temp);
			printf("current zynqmp pl temperature is: %f\n", sys_rt.sys_pl_temp );
			printf("current ambient   temperature is: %f\n", sys_rt.sys_amb_temp);
		}

		if ((sys_rt.sys_ps_temp > PLATFORM_START_TEMP_THRD) || (sys_rt.sys_pl_temp > PLATFORM_START_TEMP_THRD))
		{
			gpio_axi_reg_set(&gpio_dev, 0x00, 0x00000000);		// 风扇1启动
		} else if ((sys_rt.sys_ps_temp < (PLATFORM_START_TEMP_THRD - 5.0f)) && 
						(sys_rt.sys_pl_temp < (PLATFORM_START_TEMP_THRD  - 5.0f))){
			gpio_axi_reg_set(&gpio_dev, 0x00, 0x00000002);		//实验发现，风扇只能开关，无法调速
		}
		
		if (sys_rt.sys_amb_temp > PLATFORM_AMB_TEMP_THRD)
		{
			gpio_axi_reg_set(&gpio_dev, 0x08, 0x00000000);		// 风扇2启动
		} else if (sys_rt.sys_amb_temp < (PLATFORM_AMB_TEMP_THRD - 2.5f)) {
			gpio_axi_reg_set(&gpio_dev, 0x08, 0x00000002);
		}

		fclose(fp1);
		fclose(fp2);
		fclose(fp3);
		
        sleep(LM75A_TEMP_DELAY);
	}

	dzlog_notice("lm75a ambient temperature measure thread exit!!!");
	printf("lm75a ambient temperature measure thread exit!!!\n");
	s->status = TS_TERMINATED;
	pthread_exit(arc);
}

